Vue复习姿势系列之UI组件

您所在的位置:网站首页 element ui单选框回显 Vue复习姿势系列之UI组件

Vue复习姿势系列之UI组件

#Vue复习姿势系列之UI组件| 来源: 网络整理| 查看: 265

前言

该文章是Vue复习姿势系列的第二篇,分享单选框组件的实现过程。

脚手架请参考第一篇: juejin.cn/post/701798… 组件示例地址: oversnail.github.io/over-snail-… git地址: github.com/overSnail/o…

第一篇:Vue复习姿势系列之UI组件——按钮(Button)

介绍

基础组件,功能是提供一组备选项供用户选择,只能单选。

要实现的功能

属性

功能说明v-model/value绑定值禁用禁止使用单选框组提供一组选项给用户,v-model绑定在父级带有边框样式增强,并且提供四种尺寸按钮样式样式增加,提供四种尺寸

事件

事件名称说明回调参数change绑定值变化时的触发事件radio的value值 功能实现 1. 基础功能

src/packages目录下新建radio文件夹,文件夹内创建radio.vue和index.js。 src/styles目录下心新建radio.scss,并在src/styles/index.scss中引入。 我们用label标签将input[type=radio]及span包裹在一起。目的是让input的鼠标事件扩散到整个label上,这样即使隐藏了input元素,也能正常使用它的功能。

// radio.vue export default { name: 'myRadio', data() { return { selected: false, // 是否被选中 } }, props: {}, methods: { onClick() { this.selected = true console.log('点击事件触发') }, }, } 复制代码 // radio.scss @charset "UTF-8"; @import "common/var"; @import "mixins/mixins"; @include b(radio) { display: inline-block; box-sizing: border-box; vertical-align: top; font-size: $--font-size-large; line-height: 20px; height: 20px; margin-right: 20px; cursor: pointer; &-input { display: none; } &-icon { box-sizing: border-box; border: 1px solid #ddd; height: 14px; width: 14px; border-radius: 50%; background-color: #fff; display: inline-block; position: relative; top: 2px; &:after { content: ""; position: absolute; width: 4px; height: 4px; background-color: #fff; left: 50%; top: 50%; border-radius: 50%; transition: transform 0.2s; transform: translate(-50%,-50%) scale(0); } &-selected { background-color: $--color-primary; &:after { transform: translate(-50%,-50%) scale(1); } } } &-label { display: inline-block; margin-left: 3px; } &-selected { color: $--color-primary; } } 复制代码 2. 基础用法

首先是实现v-model和label两个属性 v-model语法糖拆开后实际上是v-bind:value和$emit("input")两个功能组成的。 考虑到初始化时v-model有可能有值,因此watch时需要immediate设置为true,这样radio初始化后能执行一次值同步。

// radio.vue export default { name: 'myRadio', data() { return { selected: false, // 是否被选中 } }, props: { value: { type: [String, Number, Boolean], default: "" }, label: { type: [String, Number, Boolean], default: "" } }, watch: { // 初始化判断是否已被选中 value: { handler(newVal) { this.selected = this.value && this.value === this.label }, immediate: true }, }, methods: { onClick() { this.selected = true this.$emit("input", this.label); }, }, } 复制代码

image.png

3. 禁用状态

利用原生radio的disabled即可。

// button.vue 部分代码省略 ...... props: { // 禁用状态 disabled: { type: Boolean, default: false, }, } ...... 复制代码

image.png

4. 单选组框 该功能实现方式是创建个radio-group组件将radio包裹,radio功能由父级接管。 会用组件通信中的$dispatch和$broadcast,前者向上派发事件,后者向下广播事件。 vue组件生命周期是由内而外的:父created -> 子created -> 子mounted -> 父mounted,父组件要在created中监听事件,不能在mounted中监听。 radio-group的disabled具体逻辑比较简单,只需根据disabled值来调整radio组件内的myDisabled属性即可。而input[type="radio"]的disabled属性由myDisabled和disabled共同决定。 创建radio-group组件: src/packages目录下新建radio-group文件夹,文件夹内创建radio-group.vue和index.js。 src/styles 目录下心新建radio-group.scss,并在src/styles/index.scss中引入。 // radio-group.vue export default { name: 'myRadioGroup', data() { return { options: [], // 选项 } }, props: { value: { type: [Boolean, String, Number], default: false, }, disabled: { type: Boolean, default: false, }, }, watch: { value: { handler(newVal) { this.syncValue(newVal) }, immediate: true, }, // 禁用状态 disabled: { handler(newVal) { this.syncOptionsDisable(newVal) }, immediate: true, }, }, created() { // 监听on-radio-add事件,将radio实例存到options上 this.$on('on-radio-add', (radio) => { this.options.push(radio) this.syncValue(this.value) this.syncOptionsDisable(this.disabled); }) // 监听on-radio-remove事件,将radio实例从options中移除 this.$on('on-radio-remove', (radio) => { this.options.splice(this.options.indexOf(radio), 1) }) // 监听radio的选中事件,做value值同步 this.$on('on-radio-select', (radio) => { this.syncValue(radio.label) }) }, methods: { /** * @description value值同步 * @param {Boolean/String/Number} focusVal 选中值,为radio组件的label属性 */ syncValue(focusVal) { this.$emit('input', focusVal) this.options.forEach((d) => { d.selected = d.label === focusVal }) }, /** * @description 设置子选项的myDisabled属性 * @param {Boolean} disabled 是否禁用 */ syncOptionsDisable(disabled) { this.options.forEach((d) => { d.myDisabled = disabled }) }, }, } 复制代码

调整radio组件代码,抛出事件给radio-group。

// radio.vue 省略部分代码 ...... ...... data() { return { selected: false, // 是否被选中 myDisabled: false, // 内部的禁用属性,交由父级控制 } }, mounted() { // 通知myRadioGroup组件调用on-radio-add方法,参数为当前radio实例 this.dispatch('myRadioGroup', 'on-radio-add', this) }, beforeDestroy() { // 移除时,调用myRadioGroup组件的on-radio-remove方法 this.dispatch('myRadioGroup', 'on-radio-remove', this) }, methods: { onClick() { this.selected = true this.$emit('input', this.label) this.dispatch("myRadioGroup", 'on-radio-select', this) }, }, ...... 复制代码

image.png

5. 带有边框 给radio组件增加border属性,可以渲染带有边框的选项,此功能主要是对css的操作。 border生效时,size同样生效。需开发4种尺寸,此功能也是对css的操作。 // radio.vue 省略部分代码 ...... ...... // 工具函数,用于判断传入的值是否符合条件 import { oneOf } from '../../utils/assist'; export default { props: { ...... // 是否绘制边框 border: { type: Boolean, default: false, }, // 尺寸 size: { validator(value) { return oneOf(value, ['large', 'medium', 'small', 'mini']) }, type: String, default: 'medium', }, ...... } } 复制代码 // radio.scss 省略部分代码 @charset "UTF-8"; @import "common/var"; @import "mixins/mixins"; @include b(radio) { ...... // size和border相关样式 &-large-border { height: 40px; padding: 8px 8px 12px 8px; border: 1px solid $--border-color; border-radius: 4px; } &-medium-border { height: 36px; padding: 6px 8px 10px 8px; border: 1px solid $--border-color; border-radius: 4px; } &-small-border { height: 32px; padding: 4px 8px 8px 8px; border: 1px solid $--border-color; border-radius: 4px; font-size: $--font-size-medium; } &-mini-border { height: 28px; padding: 2px 8px 6px 8px; border: 1px solid $--border-color; border-radius: 4px; font-size: $--font-size-medium; } } 复制代码

image.png

6. 按钮样式 将radio渲染成按钮样式,也是对css的操作。 button属性设置给radio-group,由父级接管该功能。 // radio.vue 省略部分代码 ...... data() { return { button: false, //按钮样式,由父级控制 } } 复制代码 // radio-group.vue 省略部分代码 ...... props: { ...... // 是否启用按钮样式 button: { type: Boolean, default: false } }, watch: { ...... // 是否使用按钮样式 button: { handler(newVal) { this.syncOptionsButtonStyle(newVal) }, immediate: true, } }, created() { // 监听on-radio-add事件,将radio实例存到options上 this.$on('on-radio-add', (radio) => { ...... this.syncOptionsButtonStyle(this.button); }) }, methods: { /** * @description 设置子选项的button属性,用以控制按钮样式 * @param {Boolean} value 是否设置 */ syncOptionsButtonStyle(value) { this.options.forEach((d) => { d.button = value }) } } 复制代码 // radio.scss 省略部分代码 @charset "UTF-8"; @import "common/var"; @import "mixins/mixins"; @include b(radio) { ...... // 按钮样式相关样式 &-large-button { float: left; background-color: #fff; height: 40px; line-height: 38px; padding: 0 15px 0 12px; margin: 0; border: 1px solid $--border-color; } &-medium-button { float: left; background-color: #fff; height: 36px; line-height: 34px; padding: 0 15px 0 12px; margin: 0; border: 1px solid $--border-color; } &-small-button { float: left; background-color: #fff; height: 32px; line-height: 30px; padding: 0 15px 0 12px; margin: 0; border: 1px solid $--border-color; font-size: $--font-size-medium; } &-mini-button { float: left; background-color: #fff; height: 28px; line-height: 26px; padding: 0 15px 0 12px; margin: 0; border: 1px solid $--border-color; font-size: $--font-size-medium; } } 复制代码

image.png

结语

以上便是单选框组件的部分功能开发过程,单选框组功能中我们创建了新的组件radio-group作为父级,运用组件通讯中的广播与派发机制来协调父子之间的相互调用,以此完成v-model,disabled功能的实现。

涉及知识点

1.(Vue):class与style绑定 2.(Vue):v-model语法糖原理 3.(HTML):label标签 4. (vue):组件通讯-广播与派发 5. Vue中父子组件生命周期执行顺序回顾



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3